﻿/***********************************************************************************\
| Copyright (c) 2011, Bashar Al-Rawi                                                |
| All rights reserved.                                                              |
|                                                                                   |
| Redistribution and use in source and binary forms, with or without                |
| modification, are permitted provided that the following conditions are met:       |
|    * Redistributions of source code must retain the above copyright               |
|      notice, this list of conditions and the following disclaimer.                |
|    * Redistributions in binary form must reproduce the above copyright            |
|      notice, this list of conditions and the following disclaimer in the          |
|      documentation and/or other materials provided with the distribution.         |
|    * Neither the name of the <organization> nor the                               |
|      names of its contributors may be used to endorse or promote products         |
|      derived from this software without specific prior written permission.        |
|                                                                                   |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   |
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     |
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            |
| DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY                |
| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        |
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      |
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND       |
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT        |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     |
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      |
\***********************************************************************************/

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using Microsoft.Phone.Shell;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;
using System.Xml;
using System.Xml.Linq;
using Arabic.Controls;
using Arabic.Utils;
using System.ComponentModel;

namespace Arabic.Controls
{
    public partial class RTLTextBox : UserControl
    {
        private Keyboard keyboard;
        private int direction;
        public bool Focused { get; private set; }
        //private const string StartWriting = "\uFE94\uFE91\uFE8E\uFE98\uFEDC\uFEDF\uFE8E\uFE91 \uFE83\uFEAA\uFE91\uFE8D"; // ابدأ بالكتابة
        private static Brush blackBrush = new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));

        private double CursorStartPositionX
        {
            get
            {
                if (FlowDirection == Utils.FlowDirection.LeftToRight)
                    return 20;
                else
                    return this.Width - 72;
            }
        }

        public void SetKeyboard(Keyboard kbd)
        {
            this.keyboard = kbd;
        }

        public void Serialize(string fileName)
        {
            using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream stream = isf.CreateFile(fileName))
                {
                    XmlSerializer ser = new XmlSerializer(typeof(SuperString));
                    ser.Serialize(stream, internalTextBlock.InternalText);
                }

                using (IsolatedStorageFileStream stream = isf.OpenFile(fileName, System.IO.FileMode.Open))
                {
                    XDocument doc = XDocument.Load(stream);
                }
            }
        }

        public void DeSerialize(string fileName)
        {
            try
            {
                // for now, let's just assume that the translator is arabic
                using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (isf.FileExists(fileName))
                    {
                        XmlSerializer ser = new XmlSerializer(typeof(SuperString));

                        using (IsolatedStorageFileStream stream = isf.OpenFile(fileName, System.IO.FileMode.Open))
                        {

                            try
                            {
                                internalTextBlock.InternalText = (SuperString)ser.Deserialize(stream);
                                internalTextBlock.InternalText.FixString();
                            }
                            catch (Exception ex)
                            {
                                Debug.WriteLine(ex);
                                internalTextBlock.InternalText = new SuperString();
                            }
                        }
                        isf.DeleteFile(fileName);
                    }
                    else
                    {
                        internalTextBlock.InternalText = new SuperString();
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }

        public void FocusText()
        {
            Debug.Assert(this.keyboard != null);
            this.keyboard.KeyUp += new Arabic.Controls.Key.KeyDownEventHandler(Key_KeyUp);
            Focused = true;
            border.BorderThickness = new Thickness(1);
            border.Background = ApplicationGlobals.TextboxEditBrush;
            this.internalTextBlock.Foreground = new SolidColorBrush(ForegroundColor);
            this.internalTextBlock.LayoutRoot.Background = ApplicationGlobals.TextboxEditBrush;
            BlinkCursorStoryboard.Begin();
            Update();
        }

        public void Defocus()
        {
            Focused = false;
            if (keyboard != null)
            {
                this.keyboard.KeyUp -= Key_KeyUp;
            }
            border.BorderThickness = new Thickness(0);
            border.Background = ApplicationGlobals.TextboxBrush;
            this.internalTextBlock.LayoutRoot.Background = ApplicationGlobals.TextboxBrush;
            this.internalTextBlock.Foreground = new SolidColorBrush(Color.FromArgb(150, 0, 0, 0));
            BlinkCursorStoryboard.Stop();
            Update();
        }

        public RTLTextBox()
        {
            // Required to initialize variables
            InitializeComponent();
        }

        public static readonly DependencyProperty AcceptsReturnProperty = DependencyProperty.Register(
          "AcceptsReturn", typeof(bool), typeof(RTLTextBox), new PropertyMetadata(true));
        public bool AcceptsReturn
        {
            get { return (bool)this.GetValue(AcceptsReturnProperty); }
            set { this.SetValue(AcceptsReturnProperty, value); }
        }

        public static readonly DependencyProperty CursorHeightProperty = DependencyProperty.Register(
          "CursorHeight", typeof(double), typeof(RTLTextBox), null);
        public double CursorHeight
        {
            get { return (double)this.GetValue(CursorHeightProperty); }
            set { this.SetValue(CursorHeightProperty, value); }
        }

        public static readonly DependencyProperty FlowDirectionProperty = DependencyProperty.Register(
          "FlowDirection", typeof(FlowDirection), typeof(RTLTextBox), new PropertyMetadata(FlowDirection.RightToLeft));
        public FlowDirection FlowDirection
        {
            get { return (FlowDirection)this.GetValue(FlowDirectionProperty); }
            set { this.SetValue(FlowDirectionProperty, value); }
        }

        public static readonly DependencyProperty ForegroundColorProperty = DependencyProperty.Register(
          "ForegroundColor", typeof(Color), typeof(RTLTextBox), null);

        public Color ForegroundColor
        {
            get { return (Color)this.GetValue(ForegroundColorProperty); }
            set { this.SetValue(ForegroundColorProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
        }

        public static readonly DependencyProperty TextProperty
            = DependencyProperty.Register("Text", typeof(string), typeof(RTLTextBox),
            new PropertyMetadata(new PropertyChangedCallback(RTLTextBox.OnTextPropertyChanged)));
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public void Key_KeyUp(object sender, KbdEventArgs e)
        {
            // e is null in case the even is ignored
            if (e != null)
            {
                // ignore \r if the textbox doesn't support new-line
                if (e.PlatformkeyCode == Character.ENTER && this.AcceptsReturn == false)
                    return;

                string chStr = KeyCodeHelper.Translate(e.PlatformkeyCode);
                internalTextBlock.Text += chStr;
                cursorPositionTransform.X = CursorStartPositionX + direction * this.internalTextBlock.CurrentTextBlock.ActualWidth;
            }
        }

        public string RawText
        {
            get
            {
                // THERE IS A BUG HERE. For left to right, text is shown reversed for each line. Need to investigate. Might need a big change
                if (this.FlowDirection == Utils.FlowDirection.RightToLeft)
                {
                    return internalTextBlock.InternalText;
                }
                else
                {
                    return internalTextBlock.InternalText;
                }
            }
        }

        public void Update()
        {
            internalTextBlock.Text = internalTextBlock.InternalText.DisplayText;
            cursorPositionTransform.X = CursorStartPositionX + direction * this.internalTextBlock.CurrentTextBlock.ActualWidth;
        }

        private void InitializeCurser()
        {
            direction = this.FlowDirection == Utils.FlowDirection.LeftToRight ? 1 : -1;
            this.cursorPositionTransform.X = CursorStartPositionX;
            this.cursorPositionTransform.Y = -1 * this.CursorHeight - 10;
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            this.Cursor.DataContext = this;
            this.CursorHeight = this.FontSize;
            ForegroundColor = Color.FromArgb(255, 0, 0, 0);
            this.internalTextBlock.FlowDirection = this.FlowDirection;
            InitializeCurser();
            InitializeInternalText();
            Update();
            Defocus();
        }

        private void InitializeInternalText()
        {
            this.internalTextBlock.Width = this.Width - 94;
            this.internalTextBlock.MaxWidth = this.MaxWidth;
        }

        private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //RTLTextBox text = d as RTLTextBox;
            //text.internalTextBlock.InternalText = e.NewValue.ToString();
            //text.Update();
        }

        private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!SIP.Instance.Visible)
            {
                if (sender == this)
                {
                    this.keyboard.Show();
                }
            }

            e.Handled = true;

        }

        private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            InitializeCurser();
            InitializeInternalText();
            Update();

        }


    }
}